#include "GbufferEffect.h"

GbufferEffect::GbufferEffect(const LPDIRECT3DDEVICE9 device, EffectManager *effMgr, TextureManager *texMgr) :Effect(device, effMgr, texMgr)
{
	texMgr->makeRenderTarget(L"colorMap", TextureManager::RT_FORMAT);
	texMgr->makeRenderTarget(L"normalMap", TextureManager::RT_FORMAT);
	texMgr->makeRenderTarget(L"depthMap", TextureManager::DEPTH_RT_FORMAT);
	texMgr->makeRenderTarget(L"lightMap", TextureManager::RT_FORMAT);

	device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
	device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
	device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
	device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, false);
}

GbufferEffect::~GbufferEffect(void)
{
}

void GbufferEffect::clearGBuffer(ModelMesh *quad, LPDIRECT3DSURFACE9 prevSurf)
{
	device->SetRenderTarget(0, *texMgr->getSurface(L"colorMap"));
	device->SetRenderTarget(1, *texMgr->getSurface(L"normalMap"));
	device->SetRenderTarget(2, *texMgr->getSurface(L"depthMap"));

	// Clear the render targets
	effMgr->setupEffect(GBUFFER_CLEAR_FX);
	device->BeginScene();
	effMgr->getSetEffect()->Begin(NULL, 0);
	effMgr->getSetEffect()->BeginPass(0);
	quad->getMesh()->DrawSubset(0);
	effMgr->getSetEffect()->EndPass();
	effMgr->getSetEffect()->End();
	device->EndScene();

	// Reset the render targets
	device->SetRenderTarget(0, prevSurf);
	device->SetRenderTarget(1, 0); // assumes we have nothing set
	device->SetRenderTarget(2, 0);
}

void GbufferEffect::renderGBuffer(Camera *camera, vector<ModelMesh *> meshes, LPDIRECT3DSURFACE9 prevSurf)
{
	device->SetRenderTarget(0, *texMgr->getSurface(L"colorMap"));
	device->SetRenderTarget(1, *texMgr->getSurface(L"normalMap"));
	device->SetRenderTarget(2, *texMgr->getSurface(L"depthMap"));
	device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);

	effMgr->setupEffect(GBUFFER_RENDER_FX);

	effMgr->getSetEffect()->SetMatrix("View", &(camera->getViewMatrix()));
	effMgr->getSetEffect()->SetMatrix("Projection", &(camera->getProjMatrix()));

	device->BeginScene();
	effMgr->getSetEffect()->Begin(NULL, 0);
	vector<ModelMesh *>::const_iterator itr;
	for(itr = meshes.begin();  itr != meshes.end(); itr++) 
	{
		ModelMesh *mesh = (ModelMesh *)*itr;

		if (mesh->getTextureName() != NULL)
		{
			effMgr->getSetEffect()->SetTexture("Texture", texMgr->getTexture(mesh->getTextureName()));
		} 
		else
		{
			effMgr->getSetEffect()->SetTexture("Texture", NULL);
		}

		if (mesh->getSpecTextureName() != NULL)
		{
			effMgr->getSetEffect()->SetTexture("specTexture", texMgr->getTexture(mesh->getSpecTextureName()));
		}
		else
		{
			effMgr->getSetEffect()->SetTexture("specTexture", NULL);
		}

		effMgr->getSetEffect()->SetMatrix("World", &mesh->getWorld());

		effMgr->getSetEffect()->BeginPass(0);
		mesh->getMesh()->DrawSubset(0);
		effMgr->getSetEffect()->EndPass();
	}
	effMgr->getSetEffect()->End();
	device->EndScene();

	// Reset the render targets
	device->SetRenderTarget(0, prevSurf);
	device->SetRenderTarget(1, 0); // assumes we have nothing set
	device->SetRenderTarget(2, 0);
}

void GbufferEffect::start(LPDIRECT3DSURFACE9 prevSurf)
{	
	device->SetRenderTarget(0, *texMgr->getSurface(L"lightMap"));
	device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(0, 0, 0, 0), 1.0f, 0);
	device->SetRenderTarget(0, prevSurf);
}

void GbufferEffect::combineGBuffer(ModelMesh *quad, LPDIRECT3DSURFACE9 target, LPDIRECT3DSURFACE9 prevSurf)
{
	device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
	device->SetRenderTarget(0, target);

	effMgr->setupEffect(GBUFFER_COMBINE_FX);
	effMgr->getSetEffect()->SetTexture("colorMap", texMgr->getTexture(L"colorMap"));
	effMgr->getSetEffect()->SetTexture("lightMap", texMgr->getTexture(L"lightMap"));
	effMgr->getSetEffect()->SetVector("halfPixel", &commonValues::halfPixel);

	UINT numPasses;
	device->BeginScene();
	effMgr->getSetEffect()->Begin(&numPasses, 0);
	effMgr->getSetEffect()->BeginPass(0);
	quad->getMesh()->DrawSubset(0);
	effMgr->getSetEffect()->EndPass();
	effMgr->getSetEffect()->End();
	device->EndScene();

	// Reset the render targets
	device->SetRenderTarget(0, prevSurf);
}